package com.htfyun.factorytest.agingtest;

import android.content.Context;
import android.os.Message;
import android.view.View;

import androidx.annotation.NonNull;

import com.htfyun.factorytest.R;
import com.htfyun.factorytest.config.EinkProperty;
import com.htfyun.factorytest.utils.DebugLog;
import com.htfyun.factorytest.utils.FileReadWrite;
import com.htfyun.factorytest.utils.TimeStringUtils;

import java.util.ArrayList;
import java.util.List;

public class TestEmmcCpu extends AgingTestItemBase {

    private static final int MSG_UPDATE_LOG = 100;
    private static final int MSG_DO_START_TEST = 200;
    private static final int DELAY_DO_START_TEST = 30 * 1000;

    private static final int MSG_MAX_TIMEOUT = 300;
    private static final int MSG_MIN_TIMEOUT = 400;

    private final static int MIN_TIME_TEST = 60 * 1000 * 1; //1 min
    private final static int MAX_TIME_TEST = 60 * 1000 * 90; //90 min


    public TestEmmcCpu(@NonNull Context context, @NonNull View view) {
        super(context, view);
    }

    @Override
    protected void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_UPDATE_LOG:
                if (msg.obj instanceof String) {
                    doUpdateLog((String) msg.obj);
                }
                break;
            case MSG_DO_START_TEST:
                startTestEmmcAndCpu();
                break;
            case MSG_MAX_TIMEOUT:
                maxTimeout();
                break;
            case MSG_MIN_TIMEOUT:
                minTimeout();
                break;
            default:
                break;
        }
    }

    @Override
    protected void doStartTest() {
        AgingTestItemAttr.setEmmcCpuTestOK(getContext(), true);
        startTestEmmcAndCpu();
    }

    @Override
    protected void doStopTest() {
        stopTestEmmcAndCpu();
    }

    @Override
    public AgingTestItemAttr getAgingTestItemAttr() {
        return AgingTestItemAttr.emmc_cpu;
    }

    private void updateLog(String log) {
        getHandler().obtainMessage(MSG_UPDATE_LOG, log).sendToTarget();
    }

    private void doUpdateLog(String log) {
        String txt = getTxtItemInfo();
        if (txt.length() > 1024 * 3) {
            updateTxtItemInfo(log);
        } else {
            updateTxtItemInfo(txt + "\n" + log);
        }
    }

    private void startTestEmmcAndCpu() {
        if (getAgingTestItemAttr().isTestOver(getContext())) {
            return;
        }
        startCpuTest();
        startTestEmmc();
    }

    private void stopTestEmmcAndCpu() {
        stopCpuTest();
        stopTestEmmc();
    }

    private void maxTimeout() {

        String timeout = getContext().getString(R.string.emm_cpu_max_timeout,
                TimeStringUtils.makeTimeString(MAX_TIME_TEST));
        updateLog(timeout);

        onEmmcTestOverOneTime();
    }

    private void minTimeout() {

        String timeout = getContext().getString(R.string.emm_cpu_min_timeout,
                TimeStringUtils.makeTimeString(MIN_TIME_TEST));
        updateLog(timeout);

        onEmmcTestOverOneTime();
    }

    //////////////////////////////////////////////////////////////////////////
    //test emmc

    private List<TestEmmcController.EmmcInfo> emmcTestWriteList = new ArrayList<>();
    private List<TestEmmcController.EmmcInfo> emmcTestReadList = new ArrayList<>();

    private boolean emmcOK = true;

    private long startTime = 0;

    private void startTestEmmc() {

        TestEmmcController.getInstance().stopTest();
        TestEmmcController.getInstance().deleteTestFiles();
//        FileReadWrite.deleteFile(AgingTestItemAttr.PATH_TEST_EMMC_FAIL);

        doStartTestEmmc();
    }

    private void doStartTestEmmc() {

        for (TestEmmcController.EmmcInfo info : TestEmmcController.EmmcInfo.values()) {
            if (!emmcTestWriteList.contains(info)) {
                emmcTestWriteList.add(info);
            }
            if (!emmcTestReadList.contains(info)) {
                emmcTestReadList.add(info);
            }
        }

        int count = getAgingTestItemAttr().getTestCount(getContext());

        updateLog("doStartTestEmmc Test emmc count is " + count + ", start test emmc ");
        DebugLog.e("doStartTestEmmc Test emmc count is " + count + ", start test emmc ");

        TestEmmcController.getInstance().addOnWROverListener(onWROverListener);
        TestEmmcController.getInstance().setMarginSpace((count) * TestEmmcController.HALF_G);
        TestEmmcController.getInstance().setContext(getContext());
        TestEmmcController.getInstance().startTest();

        startTime = System.currentTimeMillis();

        getHandler().sendEmptyMessageDelayed(MSG_MAX_TIMEOUT, MAX_TIME_TEST);
    }

    private void stopTestEmmc() {

        updateLog("stop test emmc");
        DebugLog.e("stop test emmc");

        TestEmmcController.getInstance().removeOnWROverListener(onWROverListener);
        TestEmmcController.getInstance().stopTest();

    }

    private void checkTestEmmcAndTryStartAgain() {
        if (!(emmcTestReadList.isEmpty() && emmcTestWriteList.isEmpty())) {
            return;
        }

        getHandler().removeMessages(MSG_MAX_TIMEOUT);

        long usedTime = System.currentTimeMillis() - startTime;
        if (usedTime < MIN_TIME_TEST) {
            String log = getContext().getString(R.string.emm_cpu_min_time_not_reached,
                    TimeStringUtils.makeTimeString(MIN_TIME_TEST),
                    TimeStringUtils.makeTimeString(usedTime)
            );

            updateLog(log);

            getHandler().sendEmptyMessageDelayed(MSG_MIN_TIMEOUT, MIN_TIME_TEST - usedTime);
            return;
        }

        onEmmcTestOverOneTime();

    }

    private void onEmmcTestOverOneTime() {

        TestEmmcController.getInstance().stopTest();

        //广播命令让他 testover 已经提前让他退出了
        if (getAgingTestItemAttr().isTestOver(getContext())) {
            return;
        }

        if (!emmcOK || !isCpuTestOk()) {

            updateLog("Test emmc and cpu failed: emmcOK = " + emmcOK + ", isCpuTestOk = " + isCpuTestOk());
            AgingTestItemAttr.setEmmcCpuTestOK(getContext(), false);
            AgingTestItemAttr.setLogForEmmcCpuTestFailed(getContext(), " Emmc:" + emmcOK + "; CPU:" + isCpuTestOk());
            getAgingTestItemAttr().setForceTestOver(getContext(), true);
            return;
        }

        int count = getAgingTestItemAttr().getTestCount(getContext());
        count++;
        getAgingTestItemAttr().setTestCount(getContext(), count);

        TestEmmcController.getInstance().deleteTestFiles();
        //等待一定时间后, 再去继续测试. 保证 activity 扫描到这个新的 testCount
        getHandler().sendEmptyMessageDelayed(MSG_DO_START_TEST, DELAY_DO_START_TEST);

    }

    private TestEmmcController.OnWROverListener onWROverListener =
            new TestEmmcController.OnWROverListener() {
                @Override
                public void onWriteOverListener(TestEmmcController.EmmcInfo info, long time_ms) {

                    updateLog("write over: emmcInfo = " + info + ", used time: " + TimeStringUtils.makeTimeString(time_ms));

                    try {
                        emmcTestWriteList.remove(info);
                    } catch (ArrayIndexOutOfBoundsException e) {
                        DebugLog.e(e.getMessage());
                    }
                    checkTestEmmcAndTryStartAgain();
                }

                @Override
                public void onReadOverListener(TestEmmcController.EmmcInfo info, long time_ms) {

                    updateLog("read over: emmcInfo = " + info + ", used time: " + TimeStringUtils.makeTimeString(time_ms));

                    try {
                        emmcTestReadList.remove(info);
                    } catch (ArrayIndexOutOfBoundsException e) {
                        DebugLog.e(e.getMessage());
                    }
                    checkTestEmmcAndTryStartAgain();

                }

                @Override
                public void onTestFailed(TestEmmcController.EmmcInfo info, String filePath, long offset, byte shouldValue, byte realValue) {

                    String log = "onTestFailed : info = " + info + ", filePath " + filePath
                            + ", offset = " + offset
                            + ", shouldValue =  0x" + Integer.toHexString((0xff & shouldValue))
                            + ", realValue = 0x" + Integer.toHexString((0xff & realValue))
                            + "\n";

                    updateLog(log);

                    DebugLog.e("EMMC error occurred, log path = " + AgingTestItemAttr.PATH_TEST_EMMC_FAIL);

                    FileReadWrite.writeAppendFile(AgingTestItemAttr.PATH_TEST_EMMC_FAIL, log);

                    emmcOK = false;

                }
            };
    //////////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////////
    // cpu test


    private void startCpuTest() {

        EinkProperty.startOrStopCpuTest(true);

        updateLog(" start Cpu Test ");

    }

    private void stopCpuTest() {

        //20190619. 老黄修改了cpu测试, 增加了mem测试, 测试时间至少2.5个小时,
        // 所以在第一阶段时, 不停止cpu测试. 让他在TestHardware里去再检测

//        EinkProperty.startOrStopCpuTest(false);

    }

    private boolean isCpuTestOk() {
        return true;

//        EinkProperty.CpuTestResultAttr attr = EinkProperty.getCpuTestResultAttr();
//        updateLog(" getCpuTestResultAttr attr = " + attr);
//
//        return (attr == EinkProperty.CpuTestResultAttr.ok);

    }

}
